/**
  Copyright (c) [2024] [JiangNan]
  [simple-go-test] is licensed under Mulan PSL v2.
  You can use this software according to the terms and conditions of the Mulan PSL v2.
  You may obtain a copy of Mulan PSL v2 at:
           http://license.coscl.org.cn/MulanPSL2
  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
  See the Mulan PSL v2 for more details.
*/

package tools

import (
	"fmt"
	"gitee.com/jn-qq/go-tools/slices"
	"github.com/xuri/excelize/v2"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"
)

type ExcelReader struct {
	f         *excelize.File
	filename  string
	sheetName string
	RowNum    int
	colNum    int
}

// NewExcelReader 创建一个ExcelReader实例
func NewExcelReader(filename, sheet string) (*ExcelReader, error) {
	er := &ExcelReader{
		filename:  filename,
		sheetName: sheet,
	}
	// 读取表格
	if file, err := os.Open(filename); err == nil {
		if er.f, err = excelize.OpenReader(file); err != nil {
			file.Close()
			return nil, err
		}
		// 获取工作表维度
		if er.RowNum, er.colNum, err = er.getSheetSize(); err != nil {
			return nil, err
		}
		return er, err
	} else {
		return nil, err
	}
}

func (er *ExcelReader) ReadSheet() ([]map[string]any, error) {
	rows, err := er.f.GetRows(er.sheetName)
	if err != nil {
		return nil, err
	}

	// 目标表头
	baseHeader := Config.Excel.GetExcelHeader()
	// 真实表头
	header := Config.Excel.UpdateExcelHeader(rows[0])

	var result = make([]map[string]any, 0, len(rows)-1)
	for rowIndex, row := range rows[1:] {
		// 设置默认字段
		var record = make(map[string]any, len(baseHeader))
		for _, baseColName := range baseHeader {
			if index := slices.Index(header, baseColName); index != -1 {
				record[baseColName] = row[index]
			} else {
				record[baseColName] = ""
			}
		}

		// 处理序号字段
		if _index, ok := record["序号"]; ok && record["序号"] != "" {
			record["序号"], _ = strconv.Atoi(_index.(string))
		} else {
			record["序号"] = rowIndex + 1
		}

		result = append(result, record)
	}

	return result, nil
}

func (er *ExcelReader) StreamReadSheet() (<-chan map[string]any, error) {

	// 创建一个通道用于发送数据
	ch := make(chan map[string]any)
	// 目标表头
	baseHeader := Config.Excel.GetExcelHeader()
	// 真实表头
	var header []string

	// 启动一个 goroutine 用于处理数据
	go func() {
		defer close(ch)
		// 流式读取表格数据
		rows, err := er.f.Rows(er.sheetName) // 修复：使用实际的工作表名称而不是硬编码的"Sheet1"
		if err != nil {
			// 修复：在单独的goroutine中发送错误并返回
			log.Printf("读取表格数据失败：%s\n%#v", er.sheetName, err)
			return
		}
		defer rows.Close()

		var currentRow int
		for rows.Next() {
			if currentRow == 0 { // 修复：正确的行索引，从0开始
				header, err = rows.Columns()
				if err != nil {
					log.Printf("读取表头失败：%s\n%#v", er.sheetName, err)
					return
				}
				header = Config.Excel.UpdateExcelHeader(header)
				currentRow += 1
				continue
			}
			row, err := rows.Columns()
			if err != nil {
				log.Printf("读取行数据失败，行号：%d\n%#v", currentRow, err)
				return
			}

			// 设置默认字段
			var record = make(map[string]any, len(baseHeader))
			for _, baseColName := range baseHeader {
				if index := slices.Index(header, baseColName); index != -1 && index < len(row) {
					record[baseColName] = row[index]
				} else {
					record[baseColName] = ""
				}
			}
			// 处理序号字段
			if _index, ok := record["序号"]; ok && record["序号"] != "" {
				record["序号"], _ = strconv.Atoi(_index.(string))
			} else {
				record["序号"] = currentRow // 修复：使用正确的行号
			}

			ch <- record

			currentRow += 1
		}

		// 检查迭代过程中的错误
		if err = rows.Error(); err != nil {
			log.Printf("遍历表格行时发生错误：%#v", err)
		}
	}()

	return ch, nil
}

// GetSheetSize 获取工作表维度
func (er *ExcelReader) getSheetSize() (int, int, error) {
	// 获取工作表维度
	dimension, err := er.f.GetSheetDimension(er.sheetName)
	if err != nil {
		return 0, 0, err
	}

	// 解析最大行号、列名
	re := regexp.MustCompile(`:([A-Z]+)(\d+)$`)
	matches := re.FindStringSubmatch(dimension)
	if len(matches) <= 2 {
		return 0, 0, fmt.Errorf("invalid dimension format")
	}
	maxRow, _ := strconv.Atoi(matches[2])
	maxCol, _ := excelize.ColumnNameToNumber(matches[1])

	return maxRow, maxCol, nil

}

func (er *ExcelReader) Close() {
	er.f.Close()
}

type ExcelWriter struct {
	f        *excelize.File
	sw       *excelize.StreamWriter
	filename string
}

func NewExcelWriter() *ExcelWriter {
	ew := &ExcelWriter{
		f:        excelize.NewFile(),
		filename: filepath.Join("result", fmt.Sprintf("out-%d.xlsx", time.Now().Unix())),
	}

	// 判断 result 目录是否存在
	_, err := os.Stat("result")
	if err != nil {
		_ = os.MkdirAll("result", os.ModePerm)
	}

	// 设置默认字体
	_ = ew.f.SetDefaultFont(Config.Excel.Style.FontName)

	_ = ew.f.SaveAs(ew.filename)

	ew.sw, _ = ew.f.NewStreamWriter("Sheet1")

	// 设置表头样式
	styleID, _ := ew.f.NewStyle(headerStyle)
	_ = ew.f.SetRowStyle("Sheet1", 1, 1, styleID)

	// 设置列宽
	for headerName, width := range Config.Excel.Style.Width {
		if index := slices.Index(Config.Excel.GetExcelHeader(), headerName); index != -1 {
			_ = ew.sw.SetColWidth(index+1, index+1, width)
		}
	}

	// 设置表头
	_ = ew.sw.SetRow("A1", slices.SliceToAny(Config.Excel.GetExcelHeader()))

	return ew
}

func (e *ExcelWriter) SaveAs() error {
	defer e.f.Close()
	defer e.sw.Flush()
	return e.f.SaveAs(e.filename)
}

func (e *ExcelWriter) Save() error {
	defer e.f.Close()
	defer e.sw.Flush()
	return e.f.Save()
}

func (e *ExcelWriter) SetRow(rowId int, value []any) error {
	cellName, _ := excelize.CoordinatesToCellName(1, rowId)
	return e.sw.SetRow(cellName, value)
}

func (e *ExcelWriter) WriteFlush() error {
	return e.sw.Flush()
}

var headerStyle = &excelize.Style{
	Font: &excelize.Font{
		Bold: true,
		Size: 12,
	},
	Alignment: &excelize.Alignment{
		Horizontal: "center",
		Vertical:   "center",
	},
}
